﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LowLevelGraphics.Filter
{
    public interface IIteratedFilter : IFilter
    {
        IFilter Filter { get; set; }
        int Iterations { get; set; }
    }

    /// <summary>
    /// This is needed to be able to specify an iteration for each filter
    /// So you might just assign a new filter to the macro as before, 
    /// or you might use an iterated filter:
    /// 
    /// MacroFilter filter = new MacroFilter();
    /// filter.FilterList.Add(new IteratedFilter(new NormalizAtion(...), 2)
    /// filter.FilterList.Add(new IteratedFilter(new BaseColorSegmentation(...), 3)
    /// 
    /// filter.Execute();  //now all iterations for each filter will be executed as specified before.
    /// 
    /// Since the IIteratedFilter-Interface inherits from IFilter IteratedFilter has all definitions
    /// of IFilter included
    /// </summary>
    public class IteratedFilter : IIteratedFilter
    {
        protected IFilter m_IFilter = null;
        protected int m_nIterations = 1;

        /// <summary>
        /// 
        /// </summary>
        public IteratedFilter()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IteratedFilter"/> class.
        /// </summary>
        /// <param name="_iFilter">The _i filter.</param>
        /// <param name="_nIterations">The _n iterations.</param>
        public IteratedFilter(IFilter _iFilter, int _nIterations)
        {
            m_IFilter = _iFilter;
            m_nIterations = _nIterations;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IteratedFilter"/> class.
        /// </summary>
        /// <param name="_iteratedFilter">The _iterated filter.</param>
        public IteratedFilter(IteratedFilter _iteratedFilter)
        {
            this.m_IFilter = (IFilter)_iteratedFilter.m_IFilter.Clone();
            m_nIterations = _iteratedFilter.m_nIterations;
        }

        /// <summary>
        /// Assign a BaseImage-Filter to an Iteratedfilter
        /// </summary>
        /// <param name="_iFilter"></param>
        /// <returns></returns>
        public static implicit operator IteratedFilter(BaseImageFilter _iFilter)
        {
            return new IteratedFilter(_iFilter, 1);
        }


        /// <summary>
        /// returns or sets the IFilter
        /// </summary>
        public IFilter Filter
        {
            get { return m_IFilter; }
            set { m_IFilter = value; }
        }

        /// <summary>
        /// Returns or sets the iterations
        /// </summary>
        public int Iterations
        {
            get { return m_nIterations; }
            set { m_nIterations = value; }
        }


        #region IFilter Members

        /// <summary>
        /// Returns or sets the steps
        /// </summary>
        public Size Step
        {
            get { return m_IFilter.Step; }
            set { m_IFilter.Step = value; }
        }

        /// <summary>
        /// Executes this filter...
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            m_IFilter.Execute(_bitmap);
            return _bitmap;
        }

        /// <summary>
        /// Executes the Filter and returns a cloned changed Image
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public UnsafeBitmap ExecuteCloned(UnsafeBitmap _bitmap)
        {
            return m_IFilter.ExecuteCloned(_bitmap);
        }

        public void ExecuteChannelled(UnsafeBitmap _bitmap, bool _bIncludeA, bool _bIncludeR, bool _bIncludeG, bool _bIncludeB)
        {
            m_IFilter.ExecuteChannelled(_bitmap, _bIncludeA, _bIncludeR, _bIncludeG, _bIncludeB);
        }

        public void ExecutedMasked(UnsafeBitmap _bitmap, UnsafeBitmap _bitmapMask)
        {
            m_IFilter.ExecutedMasked(_bitmap, _bitmapMask);
        }

        public void ExecutedMaskedChannelled(UnsafeBitmap _bitmap, UnsafeBitmap _bitmapMask, bool _bIncludeA, bool _bIncludeR, bool _bIncludeG, bool _bIncludeB)
        {
            m_IFilter.ExecutedMaskedChannelled(_bitmap, _bitmapMask, _bIncludeA, _bIncludeR, _bIncludeG, _bIncludeB);
        }

        /// <summary>
        /// Returns the UnsafeBitmap or sets it
        /// </summary>
        public UnsafeBitmap Bitmap
        {
            get { return m_IFilter.Bitmap; }
            set { m_IFilter.Bitmap = value; }
        }

        /// <summary>
        /// Returns or sets a rectangle
        /// </summary>
        public Rectangle Rectangle
        {
            get { return m_IFilter.Rectangle; }
            set { m_IFilter.Rectangle = value; }
        }

        #endregion

        #region ICloneable Members

        /// <summary>
        /// Use this to clone the filter
        /// </summary>
        /// <returns></returns>
        public virtual object Clone()
        {
            return new IteratedFilter(this);
        }

        #endregion
    }

    public class MacroFilter : BaseImageFilter
    {
        protected List<IteratedFilter> m_aFilter = new List<IteratedFilter>();

        /// <summary>
        /// Construct a new MacroFilter
        /// </summary>
        public MacroFilter()
        {
        }

        /// <summary>
        /// Declare a new MacroFilter specifying the filters
        /// </summary>
        /// <param name="_aFilter"></param>
        public MacroFilter(IEnumerable<IteratedFilter> _aFilter)
        {
            IEnumerator<IteratedFilter> aElement = _aFilter.GetEnumerator();
            while (aElement.MoveNext())
            {
                m_aFilter.Add(aElement.Current);
            }
        }

        /// <summary>
        /// List all Filters
        /// </summary>
        public List<IteratedFilter> FilterList
        {
            get { return m_aFilter; }
            set { m_aFilter = value; }
        }

        /// <summary>
        /// Now this can also be used to specify the iterations for the execution of each filter
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            foreach (IteratedFilter filter in m_aFilter)
            {
                for (int i = 0; i < filter.Iterations; i++)
                {
#if DEBUG
                    //TODO: This shouldn't be necessary
                    _bitmap.UnlockImage();
                    _bitmap.LockImage();
#endif
                    filter.Execute(_bitmap);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// Foreach Filter...
        /// </summary>
        /// <returns></returns>
        public IEnumerator<IteratedFilter> GetEnumerator()
        {
            return this.m_aFilter.GetEnumerator();
        }

        /// <summary>
        /// To clone this filter, each filter in list has to be cloned
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            MacroFilter filter = new MacroFilter();
            foreach (IteratedFilter filterTemp in this.FilterList)
            {
                filter.FilterList.Add((IteratedFilter)filterTemp.Clone());
            }
            return filter;
        }
    }
}
